﻿using System;
using System.Runtime.InteropServices;
using ArgusLib.InteropServices;
using ArgusLib.FFmpeg.avutil;

namespace ArgusLib.FFmpeg.swscale.Interop
{
	static class Functions
	{
		static Functions()
		{
			//Log.Initialize();
		}

		/// <summary>
		/// Check if context can be reused, otherwise reallocate a new one.
		///
		/// If context is NULL, just calls sws_getContext() to get a new
		/// context. Otherwise, checks if the parameters are the ones already
		/// saved in context. If that is the case, returns the current
		/// context. Otherwise, frees context and gets a new context with
		/// the new parameters.
		///
		/// Be warned that srcFilter and dstFilter are not checked, they
		/// are assumed to remain the same.
		/// </summary>
		/// <param name="sourceWidth">The width of the source image.</param>
		/// <param name="sourceHeight">The height of the source image.</param>
		/// <param name="sourcePixelFormat">The source image format.</param>
		/// <param name="destWidth">The width of the destination image.</param>
		/// <param name="destHeight">The height of the destination image.</param>
		/// <param name="destPixelFormat">The destination image format.</param>
		/// <param name="flags">Specify which algorithm and options to use for rescaling .</param>
		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		public static extern IntPtr sws_getCachedContext(
			IntPtr context,
			int sourceWidth, int sourceHeight, AVPixelFormat sourcePixelFormat,
			int destWidth, int destHeight, AVPixelFormat destPixelFormat,
			SWS_Flags flags,
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsFilter>))]
			SwsFilter sourceFilter,
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsContext>))]
			SwsFilter destFilter,
			IntPtr param);

		/// <summary>
		/// Check if context can be reused, otherwise reallocate a new one.
		///
		/// If context is NULL, just calls sws_getContext() to get a new
		/// context. Otherwise, checks if the parameters are the ones already
		/// saved in context. If that is the case, returns the current
		/// context. Otherwise, frees context and gets a new context with
		/// the new parameters.
		///
		/// Be warned that srcFilter and dstFilter are not checked, they
		/// are assumed to remain the same.
		/// </summary>
		/// <param name="sourceWidth">The width of the source image.</param>
		/// <param name="sourceHeight">The height of the source image.</param>
		/// <param name="sourcePixelFormat">The source image format.</param>
		/// <param name="destWidth">The width of the destination image.</param>
		/// <param name="destHeight">The height of the destination image.</param>
		/// <param name="destPixelFormat">The destination image format.</param>
		/// <param name="flags">Specify which algorithm and options to use for rescaling .</param>
		[DllImport(FFmpegDll.swscale, CallingConvention = FFmpegDll.CallingConvention)]
		[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsContext>))]
		public static extern SwsContext sws_getCachedContext(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsContext>), MarshalCookie = ArgusMarshalerCookies.SkipNativeCleanUp)]
			SwsContext context,
			int sourceWidth, int sourceHeight, AVPixelFormat sourcePixelFormat,
			int destWidth, int destHeight, AVPixelFormat destPixelFormat,
			SWS_Flags flags,
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsFilter>))]
			SwsFilter sourceFilter,
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsContext>))]
			SwsFilter destFilter,
			IntPtr param);

		/// <summary>
		/// Allocate and return an uninitialized vector with length coefficients.
		/// </summary>
		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
		public static extern SwsVector sws_allocVec(int length);

		/// <summary>
		/// Return a normalized Gaussian curve used to filter stuff
		/// quality = 3 is high quality, lower is lower quality.
		/// </summary>
		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
		public static extern SwsVector sws_getGaussianVec(double variance, double quality);

		/// <summary>
		/// Allocate and return a vector with length coefficients, all
		/// with the same value c.
		/// </summary>
		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
		public static extern SwsVector sws_getConstVec(double c, int length);

		/// <summary>
		/// Allocate and return a vector with just one coefficient, with
		/// value 1.0.
		/// </summary>
		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
		public static extern SwsVector sws_getIdentityVec();

		/// <summary>
		/// Scale all the coefficients of a by the scalar value.
		/// </summary>
		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		public static extern void sws_scaleVec(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
			SwsVector a, double scalar);

		/// <summary>
		/// Scale all the coefficients of a so that their sum equals height.
		/// </summary>
		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		public static extern void sws_normalizeVec(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
			SwsVector a, double height);

		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		public static extern void sws_convVec(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
			SwsVector a,
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
			SwsVector b);

		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		public static extern void sws_addVec(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
			SwsVector a,
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
			SwsVector b);

		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		public static extern void sws_subVec(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
			SwsVector a,
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
			SwsVector b);

		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		public static extern void sws_shiftVec(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
			SwsVector a, int shift);

		/// <summary>
		/// Allocate and return a clone of the vector a, that is a vector
		/// with the same coefficients as a.
		/// </summary>
		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
		public static extern SwsVector sws_cloneVec(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>))]
			SwsVector a);

		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		public static extern void sws_freeVec(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsVector>), MarshalCookie = ArgusMarshalerCookies.SkipNativeCleanUp)]
			SwsVector a);

		/// <summary>
		/// Free the swscaler context swsContext.
		/// If swsContext is NULL, then does nothing.
		/// </summary>
		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		public static extern void sws_freeContext(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsContext>), MarshalCookie = ArgusMarshalerCookies.SkipNativeCleanUp)]
			SwsContext swsContext);

		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsFilter>))]
		public static extern SwsFilter sws_getDefaultFilter(
			float lumaGBlur, float chromaGBlur,
			float lumaSharpen, float chromaSharpen,
			float chromaHShift, float chromaVShift,
			int verbose);

		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		public static extern void sws_freeFilter(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsFilter>), MarshalCookie = ArgusMarshalerCookies.SkipNativeCleanUp)]
			SwsFilter filter);

		/// <summary>
		/// Scale the image slice in srcSlice and put the resulting scaled
		/// slice in the image in dst. A slice is a sequence of consecutive
		/// rows in an image.
		///
		/// Slices have to be provided in sequential order, either in
		/// top-bottom or bottom-top order. If slices are provided in
		/// non-sequential order the behavior of the function is undefined.
		/// </summary>
		/// <param name="swsContext">The scaling context previously created with <see cref="sws_getCachedContext"/>.</param>
		/// <param name="srcSlice">The array containing the pointers to the planes of the source slice.</param>
		/// <param name="srcStride">The array containing the strides for each plane of the source image.</param>
		/// <param name="srcSliceY">
		/// The position in the source image of the slice to
		/// process, that is the number (counted starting from
		/// zero) in the image of the first row of the slice.
		/// </param>
		/// <param name="srcSliceH">The height of the source slice, that is the number of rows in the slice.</param>
		/// <param name="dst">The array containing the pointers to the planes of the destination image.</param>
		/// <param name="dstStride">The array containing the strides for each plane of the destination image.</param>
		/// <returns>The height of the output slice.</returns>
		[DllImport(FFmpegDll.swscale, CallingConvention=FFmpegDll.CallingConvention)]
		public static extern int sws_scale(
			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArgusMarshaler<SwsContext>))]
			SwsContext swsContext,
			IntPtr[] srcSlice, int[] srcStride, int srcSliceY, int srcSliceH,
            IntPtr[] dst, int[] dstStride);
	}
}
